using System.Collections.Generic;

namespace TLDRML
{
    internal class CachedEnumerable<T> : IEnumerable<T>
    {
        private readonly IEnumerator<T> baseEnumerator;
        private readonly IList<T> cachedItems = new List<T>();

        public CachedEnumerable(IEnumerable<T> enumerable)
        {
            baseEnumerator = enumerable.GetEnumerator();
        }

        bool CacheNextItem(int currentIndex)
        {
            lock (baseEnumerator)
            {
                while (currentIndex >= cachedItems.Count)
                {
                    if (!baseEnumerator.MoveNext())
                        return false;
                    cachedItems.Add(baseEnumerator.Current);
                }
            }
            return true;
        }

        public IEnumerator<T> GetEnumerator()
        {
            int currentIndex = 0;

            while (currentIndex < cachedItems.Count
                    || CacheNextItem(currentIndex))
            {
                yield return cachedItems[currentIndex++];
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}